`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/04 19:25:31
// Design Name: 
// Module Name: branch
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

//˫�����֧Ԥ��
//ע��
//��1��ֻ��branch_taken==1ʱ��branch_traget��ֵ�Żᱻ�õ������ܸ���BTB��
//     ������ⲿ��ID�׶��Ƿ���ֱ�Ӹ���branch_taken���Ƿ������ת����
//     ������ܣ���Ҫ�Ӷ�Ӧ��������ж�
//��2����������ǻ���IF��ID����һ��ʱ�ӣ�ֻ��¼���ϴε�ַlast_PC����ID������ж�Ӧ
//     �����ǣ�����ַ����IFʱ��ͬʱ���뵽branch�У�branchԤ����һʱ�ӵ���ת��ַ��IF
//              ��������һʱ�ӵ�IDҲ�ܸ���branch_taken�Ľ��
//    ����������ż���ˮ�У�IF��branch��ID
//    IF��ID���������ʱ�ӣ���Ҫ���¸Ĵ��룬
//    ��Ҫ��¼���ϴε�ַlast_last_PC��Ȼ���ID��branch_taken��branch_traget��Ӧ����

module branchPredictionUnit (
  input clk,
  input rst,
  input [31:0] pc_address,  // ����PC��ַ ָ��1
  input [31:0] pc_address2, //����PC��ַ ָ��2
  input branch_taken,       // ����ָ��1�Ƿ���ת     ID�׶θ�
  input [31:0] branch_traget,      //ָ��1��ת��ַ   ID�׶θ�  ��branch_takenΪ1ʱ�����ֵ�ű��õ�
  input branch_taken2,       // ����ָ��2�Ƿ���ת    ID�׶θ�
  input [31:0] branch_traget2,      //ָ��2��ת��ַ  ID�׶θ�
 
  output wire branch_prediction,   // ���ָ��1Ԥ����
  output wire [31:0] branch_prediction_traget, //���ָ��1��ת��ַ
  output wire branch_prediction2,   // ���ָ��2Ԥ����
  output wire [31:0] branch_prediction_traget2 //���ָ��2��ת��ַ
);

  parameter TABLE_SIZE = 1024;    // PHT������С
  parameter COUNTER_WIDTH = 2;    // PHT����������
  reg [COUNTER_WIDTH-1:0] PHT [0:TABLE_SIZE-1]; //PHT��
  reg [63:0] BTB [0:TABLE_SIZE-1];              //BTB��
  integer      i;

// ָ��1
  reg [31:0] last_PC=32'b0;     //��¼��һ��PC��ַ
  reg [9:0] index;              //��PC��10λ����PHT��
  reg       taken;              //��¼������
  
// ָ��2
  reg [31:0] last_PC2=32'b0;     //��¼��һ��PC��ַ
  reg [9:0] index2;              //��PC��10λ����PHT��
  reg       taken2;              //��¼������
  
  always @(posedge clk or negedge rst) begin
    if(!rst)begin      //PHT��BTB����ʼ��
        for (i = 0; i < TABLE_SIZE; i = i + 1) begin
            PHT[i] <= 2'b01;        //��ʼֵ��01
            BTB[i] <= 2'b00;
        end
    end
    else begin         
        last_PC[31:0]<=pc_address[31:0];
        index[9:0]<=pc_address[9:0];
        last_PC2[31:0]<=pc_address2[31:0];
        index2[9:0]<=pc_address2[9:0];
        taken=branch_taken;
        taken2=branch_taken2;
        case(taken)                     //��ָ��1����PHT��
            1'b0 : begin            
                        if(PHT[last_PC[9:0]]==2'b00) begin
                             PHT[last_PC[9:0]]=0;
                        end
                        else begin
                            PHT[last_PC[9:0]] = PHT[last_PC[9:0]]-2'b01;
                        end
                    end
            1'b1 : begin        //ֻ������תָ�������£��Ÿ���BTB��
                        if(PHT[last_PC[9:0]]==2'b11) begin
                            PHT[last_PC[9:0]]=2'b11;
                            BTB[last_PC[9:0]]={last_PC[31:0],branch_traget[31:0]}; 
                        end
                        else begin
                            PHT[last_PC[9:0]] = PHT[last_PC[9:0]]+2'b01;
                            BTB[last_PC[9:0]]={last_PC[31:0],branch_traget[31:0]}; 
                        end
                    end
        endcase
        case(taken2)            //��ָ��2����PHT��
            1'b0 : begin            
                        if(PHT[last_PC2[9:0]]==2'b00) begin
                             PHT[last_PC2[9:0]]=0;
                        end
                        else begin
                            PHT[last_PC2[9:0]] = PHT[last_PC2[9:0]]-2'b01;
                        end
                    end
            1'b1 : begin        //ֻ������תָ�������£��Ÿ���BTB��
                        if(PHT[last_PC2[9:0]]==2'b11) begin
                            PHT[last_PC2[9:0]]=2'b11;
                            BTB[last_PC2[9:0]]={last_PC2[31:0],branch_traget2[31:0]}; 
                        end
                        else begin
                            PHT[last_PC2[9:0]] = PHT[last_PC2[9:0]]+2'b01;
                            BTB[last_PC2[9:0]]={last_PC2[31:0],branch_traget2[31:0]}; 
                        end
                    end
        endcase
    end
  end

//ָ��1����BTB�� 
assign branch_prediction=PHT[pc_address[9:0]][1];
//���PC��ַ��BTB����ַһ�£��������ת��ַ���������ȫ0��
assign branch_prediction_traget= (pc_address==BTB[pc_address[9:0]][63:32]) ? BTB[pc_address[9:0]][31:0]: 32'b0;

//ָ��2����BTB�� 
assign branch_prediction2=PHT[pc_address2[9:0]][1];
assign branch_prediction_traget2= (pc_address2==BTB[pc_address2[9:0]][63:32]) ? BTB[pc_address2[9:0]][31:0]: 32'b0;
endmodule

